package cn.ac.iie.di.ban.news.server.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

/**
 * Created by Black-Laptop on 8/17/2017.
 */
public class HttpUtils {

    public static Logger logger = Logger.getLogger(HttpUtils.class);
    private static HttpClient httpsclient = null;
    private static HttpClient httpclient = null;

    private static synchronized void init() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException, CertificateException, UnrecoverableKeyException {
        if (httpclient == null) {
            synchronized (HttpUtils.class) {
                if (httpclient == null) {
                    httpclient = HttpClients.createDefault();
                }
            }
        }
        if (httpsclient == null) {
            synchronized (HttpUtils.class) {
                if (httpsclient == null) {

                    //key manager
                    KeyStore keyStore = KeyStore.getInstance("JKS");
                    keyStore.load(ClassLoader.getSystemResourceAsStream("news_client_private.keystore"), "123456".toCharArray());
                    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                    kmf.init(keyStore, "123456".toCharArray());
                    KeyManager[] km = kmf.getKeyManagers();

                    //trust manager
                    KeyStore trustStore = KeyStore.getInstance("JKS");
                    logger.debug("httputils trust file: " + ClassLoader.getSystemResource("news_server_public.keystore"));
                    trustStore.load(ClassLoader.getSystemResourceAsStream("news_server_public.keystore"), "123456".toCharArray());
                    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
                    tmf.init(trustStore);
                    TrustManager[] tm = tmf.getTrustManagers();
                    TrustManager[] tm4dgb = {new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                        }

                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
                    }};

                    SSLContext sslContext = SSLContext.getInstance("TLS");
                    sslContext.init(km, tm, null);

                    httpsclient = HttpClients.custom()
                            .setSSLContext(sslContext)
                            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                            .build();
                }
            }
        }

    }

    public static Result httpsPost(String url, HashMap<String, String> paramPair) throws Exception {
        init();
        if (url.endsWith("/")) {
        } else {
            url += "/";
        }
        HttpPost post = new HttpPost(url);
        if (paramPair != null) {
            List<NameValuePair> params = new ArrayList<>(paramPair.size());
            for (Map.Entry<String, String> entry : paramPair.entrySet()) {
                params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            post.setEntity(new UrlEncodedFormEntity(params));
        }
        HttpResponse response = httpsclient.execute(post);
        Result rslt = new Result();
        rslt.statusCode = response.getStatusLine().getStatusCode();
        rslt.reasonPhrase = response.getStatusLine().getReasonPhrase();
        BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        String line;
        while ((line = br.readLine()) != null) {
            if (rslt.content == null) {
                rslt.content = line;
            } else {
                rslt.content += "\n" + line;
            }

        }
        return rslt;
    }

    public static Result httpPost(String url, HashMap<String, String> paramPair) throws Exception {
        init();
        if (url.endsWith("/")) {
        } else {
            url += "/";
        }
        HttpPost post = new HttpPost(url);
        if (paramPair != null) {
            List<NameValuePair> params = new ArrayList<>(paramPair.size());
            for (Map.Entry<String, String> entry : paramPair.entrySet()) {
                params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            post.setEntity(new UrlEncodedFormEntity(params));
        }
        HttpResponse response = httpclient.execute(post);
        Result rslt = new Result();
        rslt.statusCode = response.getStatusLine().getStatusCode();
        rslt.reasonPhrase = response.getStatusLine().getReasonPhrase();
        BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        String line;
        while ((line = br.readLine()) != null) {
            if (rslt.content == null) {
                rslt.content = line;
            } else {
                rslt.content += "\n" + line;
            }

        }
        return rslt;
    }

    /**
     * 发送get请求
     *
     * @param url 路径
     * @return
     */
    public static String httpGet(String url) {
        //get请求返回结果
        String strResult = null;
        try {
            DefaultHttpClient client = new DefaultHttpClient();
            //发送get请求
            HttpGet request = new HttpGet(url);
            HttpResponse response = null;
            try {
                response = client.execute(request);
            } catch (IOException e) {
                logger.error(ExceptionUtils.getStackTrace(e));
            }

            /**
             * 请求发送成功，并得到响应*
             */
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                /**
                 * 读取服务器返回过来的json字符串数据*
                 */
                strResult = EntityUtils.toString(response.getEntity());
                /**
                 * 把json字符串转换成json对象*
                 */
                url = URLDecoder.decode(url, "UTF-8");
            } else {
                logger.error("get请求提交失败:" + url);
            }
        } catch (IOException e) {
            logger.error("get请求提交失败:" + url, e);
        }
        return strResult;
    }

    public static class Result {

        public int statusCode;
        public String reasonPhrase;
        public String content;

        @Override
        public String toString() {
            return "{statusCode=" + statusCode + ", reasonPhrase=" + reasonPhrase + ", content=" + content + "}";
        }

    }
}
